#include "ParametricKuenDemo.h"

#include <array>

// These callbacks do the actual work.
// Callbacks for the interactions
class SliderCallbackMinimumU : public vtkCommand
{
public:
	static SliderCallbackMinimumU* New()
	{
		return new SliderCallbackMinimumU;
	}
	virtual void Execute(vtkObject* caller, unsigned long, void*)
	{
		vtkSliderWidget* sliderWidget = reinterpret_cast<vtkSliderWidget*>(caller);
		double value = static_cast<vtkSliderRepresentation2D*>(
			sliderWidget->GetRepresentation())
			->GetValue();
		if (value > .9 * this->Kuen->GetMaximumU())
		{
			value = .99 * this->Kuen->GetMaximumU();
			static_cast<vtkSliderRepresentation2D*>(sliderWidget->GetRepresentation())
				->SetValue(value);
		}
		this->Kuen->SetMinimumU(value);
	}
	SliderCallbackMinimumU() : Kuen(0)
	{
	}
	vtkParametricKuen* Kuen;
};
class SliderCallbackMaximumU : public vtkCommand
{
public:
	static SliderCallbackMaximumU* New()
	{
		return new SliderCallbackMaximumU;
	}
	virtual void Execute(vtkObject* caller, unsigned long, void*)
	{
		vtkSliderWidget* sliderWidget = reinterpret_cast<vtkSliderWidget*>(caller);
		double value = static_cast<vtkSliderRepresentation2D*>(
			sliderWidget->GetRepresentation())
			->GetValue();
		if (value < this->Kuen->GetMinimumU() + .01)
		{
			value = this->Kuen->GetMinimumU() + .01;
			static_cast<vtkSliderRepresentation2D*>(sliderWidget->GetRepresentation())
				->SetValue(value);
		}
		this->Kuen->SetMaximumU(static_cast<vtkSliderRepresentation2D*>(
			sliderWidget->GetRepresentation())
			->GetValue());
	}
	SliderCallbackMaximumU() : Kuen(0)
	{
	}
	vtkParametricKuen* Kuen;
};

class SliderCallbackMinimumV : public vtkCommand
{
public:
	static SliderCallbackMinimumV* New()
	{
		return new SliderCallbackMinimumV;
	}
	virtual void Execute(vtkObject* caller, unsigned long, void*)
	{
		vtkSliderWidget* sliderWidget = reinterpret_cast<vtkSliderWidget*>(caller);
		double value = static_cast<vtkSliderRepresentation2D*>(
			sliderWidget->GetRepresentation())
			->GetValue();
		if (value > .9 * this->Kuen->GetMaximumV())
		{
			value = .9 * this->Kuen->GetMaximumV();
			static_cast<vtkSliderRepresentation2D*>(sliderWidget->GetRepresentation())
				->SetValue(value);
		}
		this->Kuen->SetMinimumV(value);
	}
	SliderCallbackMinimumV() : Kuen(0)
	{
	}
	vtkParametricKuen* Kuen;
};

class SliderCallbackMaximumV : public vtkCommand
{
public:
	static SliderCallbackMaximumV* New()
	{
		return new SliderCallbackMaximumV;
	}
	virtual void Execute(vtkObject* caller, unsigned long, void*)
	{
		vtkSliderWidget* sliderWidget = reinterpret_cast<vtkSliderWidget*>(caller);
		double value = static_cast<vtkSliderRepresentation2D*>(
			sliderWidget->GetRepresentation())
			->GetValue();
		if (value < this->Kuen->GetMinimumV() + .01)
		{
			value = this->Kuen->GetMinimumV() + .01;
			static_cast<vtkSliderRepresentation2D*>(sliderWidget->GetRepresentation())
				->SetValue(value);
		}
		this->Kuen->SetMaximumV(static_cast<vtkSliderRepresentation2D*>(
			sliderWidget->GetRepresentation())
			->GetValue());
	}
	SliderCallbackMaximumV() : Kuen(0)
	{
	}
	vtkParametricKuen* Kuen;
};
ParametricKuenDemo::ParametricKuenDemo(QWidget* parent)
	: QMainWindow(parent)
{
	vtkWidget = new QVTKOpenGLNativeWidget(this);
	this->resize(600, 400);
	this->setCentralWidget(vtkWidget);

	vtkNew<vtkNamedColors> colors;

	// Set the background color.
	std::array<unsigned char, 4> bkg{ {26, 51, 102, 255} };
	colors->SetColor("BkgColor", bkg.data());

	vtkNew<vtkParametricKuen> surface;
	vtkNew<vtkParametricFunctionSource> source;

	vtkNew<vtkRenderer> renderer;
	vtkNew<vtkPolyDataMapper> mapper;
	vtkNew<vtkActor> actor;

	vtkNew<vtkProperty> backProperty;
	backProperty->SetColor(colors->GetColor3d("Tomato").GetData());

	// Create a parametric function source, renderer, mapper, and actor
	source->SetParametricFunction(surface);

	mapper->SetInputConnection(source->GetOutputPort());

	actor->SetMapper(mapper);
	actor->SetBackfaceProperty(backProperty);
	actor->GetProperty()->SetDiffuseColor(colors->GetColor3d("Banana").GetData());
	actor->GetProperty()->SetSpecular(.5);
	actor->GetProperty()->SetSpecularPower(20);

	vtkWidget->renderWindow()->AddRenderer(renderer);
	renderer->AddActor(actor);
	renderer->SetBackground(colors->GetColor3d("BkgColor").GetData());
	renderer->ResetCamera();
	renderer->GetActiveCamera()->Azimuth(30);
	renderer->GetActiveCamera()->Elevation(-30);
	renderer->GetActiveCamera()->Zoom(0.9);
	renderer->ResetCameraClippingRange();

	// Setup a slider widget for each varying parameter
	double tubeWidth(.008);
	double sliderLength(.008);
	double titleHeight(.02);
	double labelHeight(.02);

	sliderRepMinimumU->SetMinimumValue(-4.5);
	sliderRepMinimumU->SetMaximumValue(4.5);
	sliderRepMinimumU->SetValue(-4.5);
	sliderRepMinimumU->SetTitleText("U min");

	sliderRepMinimumU->GetPoint1Coordinate()
		->SetCoordinateSystemToNormalizedDisplay();
	sliderRepMinimumU->GetPoint1Coordinate()->SetValue(.1, .1);
	sliderRepMinimumU->GetPoint2Coordinate()
		->SetCoordinateSystemToNormalizedDisplay();
	sliderRepMinimumU->GetPoint2Coordinate()->SetValue(.9, .1);

	sliderRepMinimumU->SetTubeWidth(tubeWidth);
	sliderRepMinimumU->SetSliderLength(sliderLength);
	sliderRepMinimumU->SetTitleHeight(titleHeight);
	sliderRepMinimumU->SetLabelHeight(labelHeight);

	sliderWidgetMinimumU->SetInteractor(vtkWidget->interactor());
	sliderWidgetMinimumU->SetRepresentation(sliderRepMinimumU);
	sliderWidgetMinimumU->SetAnimationModeToAnimate();
	sliderWidgetMinimumU->EnabledOn();

	vtkNew<SliderCallbackMinimumU> callbackMinimumU;
	callbackMinimumU->Kuen = surface;

	sliderWidgetMinimumU->AddObserver(vtkCommand::InteractionEvent,
		callbackMinimumU);


	sliderRepMaximumU->SetMinimumValue(-4.5);
	sliderRepMaximumU->SetMaximumValue(4.5);
	sliderRepMaximumU->SetValue(4.5);
	sliderRepMaximumU->SetTitleText("U max");

	sliderRepMaximumU->GetPoint1Coordinate()
		->SetCoordinateSystemToNormalizedDisplay();
	sliderRepMaximumU->GetPoint1Coordinate()->SetValue(.1, .9);
	sliderRepMaximumU->GetPoint2Coordinate()
		->SetCoordinateSystemToNormalizedDisplay();
	sliderRepMaximumU->GetPoint2Coordinate()->SetValue(.9, .9);

	sliderRepMaximumU->SetTubeWidth(tubeWidth);
	sliderRepMaximumU->SetSliderLength(sliderLength);
	sliderRepMaximumU->SetTitleHeight(titleHeight);
	sliderRepMaximumU->SetLabelHeight(labelHeight);

	sliderWidgetMaximumU->SetInteractor(vtkWidget->interactor());
	sliderWidgetMaximumU->SetRepresentation(sliderRepMaximumU);
	sliderWidgetMaximumU->SetAnimationModeToAnimate();
	sliderWidgetMaximumU->EnabledOn();

	vtkNew<SliderCallbackMaximumU> callbackMaximumU;
	callbackMaximumU->Kuen = surface;

	sliderWidgetMaximumU->AddObserver(vtkCommand::InteractionEvent,
		callbackMaximumU);

	vtkNew<vtkSliderRepresentation2D> sliderRepMinimumV;

	sliderRepMinimumV->SetMinimumValue(0.05);
	sliderRepMinimumV->SetMaximumValue(vtkMath::Pi());
	sliderRepMinimumV->SetValue(0.0);
	sliderRepMinimumV->SetTitleText("V min");

	sliderRepMinimumV->GetPoint1Coordinate()
		->SetCoordinateSystemToNormalizedDisplay();
	sliderRepMinimumV->GetPoint1Coordinate()->SetValue(.1, .1);
	sliderRepMinimumV->GetPoint2Coordinate()
		->SetCoordinateSystemToNormalizedDisplay();
	sliderRepMinimumV->GetPoint2Coordinate()->SetValue(.1, .9);

	sliderRepMinimumV->SetTubeWidth(tubeWidth);
	sliderRepMinimumV->SetSliderLength(sliderLength);
	sliderRepMinimumV->SetTitleHeight(titleHeight);
	sliderRepMinimumV->SetLabelHeight(labelHeight);

	sliderWidgetMinimumV->SetInteractor(vtkWidget->interactor());
	sliderWidgetMinimumV->SetRepresentation(sliderRepMinimumV);
	sliderWidgetMinimumV->SetAnimationModeToAnimate();
	sliderWidgetMinimumV->EnabledOn();

	vtkNew<SliderCallbackMinimumV> callbackMinimumV;
	callbackMinimumV->Kuen = surface;

	sliderWidgetMinimumV->AddObserver(vtkCommand::InteractionEvent,
		callbackMinimumV);


	sliderRepMaximumV->SetMinimumValue(0.05);
	sliderRepMaximumV->SetMaximumValue(vtkMath::Pi() - .05);
	sliderRepMaximumV->SetValue(vtkMath::Pi());
	sliderRepMaximumV->SetTitleText("V max");

	sliderRepMaximumV->GetPoint1Coordinate()
		->SetCoordinateSystemToNormalizedDisplay();
	sliderRepMaximumV->GetPoint1Coordinate()->SetValue(.9, .1);
	sliderRepMaximumV->GetPoint2Coordinate()
		->SetCoordinateSystemToNormalizedDisplay();
	sliderRepMaximumV->GetPoint2Coordinate()->SetValue(.9, .9);
	sliderRepMaximumV->SetTubeWidth(tubeWidth);
	sliderRepMaximumV->SetSliderLength(sliderLength);
	sliderRepMaximumV->SetTitleHeight(titleHeight);
	sliderRepMaximumV->SetLabelHeight(labelHeight);

	sliderWidgetMaximumV->SetInteractor(vtkWidget->interactor());
	sliderWidgetMaximumV->SetRepresentation(sliderRepMaximumV);
	sliderWidgetMaximumV->SetAnimationModeToAnimate();
	sliderWidgetMaximumV->EnabledOn();

	vtkNew<SliderCallbackMaximumV> callbackMaximumV;
	callbackMaximumV->Kuen = surface;

	sliderWidgetMaximumV->AddObserver(vtkCommand::InteractionEvent,
		callbackMaximumV);

	surface->SetMinimumU(-4.5);
	surface->SetMaximumU(4.5);
	surface->SetMinimumV(0.05);
	surface->SetMaximumV(vtkMath::Pi() - .05);

	renderer->ResetCamera();
	renderer->GetActiveCamera()->Azimuth(30);
	renderer->GetActiveCamera()->Elevation(-30);
	renderer->GetActiveCamera()->Zoom(0.9);
	renderer->ResetCameraClippingRange();
}
